/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package dnbW.entityW;

import dnbW.dbW.DataSource;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Encapsulates a data-storing attribute type in the database (corresponding to relational column)
 * @author truongbaquan
 */
public class Attribute implements IPath {
    public static final int NUMBER_OF_SAMPLE_VALUES = 10;

    // <editor-fold defaultstate="collapsed" desc="Decorator Pattern">
    // <editor-fold defaultstate="collapsed" desc="Path">
    private IPath path;

    public IPath getPath() {
        return path;
    }
    // </editor-fold>

    @Override
    public DataSource getDataSource() {
        return path.getDataSource();
    }

    @Override
    public String[] getElements() {
        return path.getElements();
    }

    @Override
    public String getElementAtLevel(int level) {
        return path.getElementAtLevel(level);
    }

    @Override
    public boolean isAttribute() {
        return path.isAttribute();
    }

    @Override
    public int getLevel() {
        return path.getLevel();
    }

    @Override
    public String toSQLPathExp() {
        return path.toSQLPathExp();
    }

    @Override
    public String toPathExp() {
        return path.toPathExp();
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Entity">
    private IEntity entity;

    public IEntity getEntity() {
        return entity;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Frequency (get/set)">
    /**
     * The number of entity nodes having this attribute
     */
    private int frequency;

    public int getFrequency() {
        return frequency;
    }

    public void setFrequency(int frequency) {
        this.frequency = frequency;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Sample Values">
    private Map<String, SampleValue> sampleValues = new HashMap<String, SampleValue>();

    public Collection<SampleValue> getSampleValues() {
        return this.sampleValues.values();
    }
    
    public void addSampleValue(SampleValue sampleValue) {
        this.sampleValues.put(sampleValue.getValue(), sampleValue);
    }
    
    public void addSampleValue(String value, int frequency) {
        SampleValue sampleValue = new SampleValue(this, value);
        sampleValue.setFrequency(frequency);
        this.addSampleValue(sampleValue);
    }

    /**
     * Gets a sample value with weighted probability
     * @return
     */
    public String getRandomSampleValue() {
        int totalFreq = 0;
        for (SampleValue sampleValue : this.getSampleValues()) {
            totalFreq += sampleValue.getFrequency();
        }
        int dice = (int)(Math.random()*totalFreq);

        int countFreq = 0; String lastValue = null; String returnValue;
        for (SampleValue sampleValue : this.getSampleValues()) {
            countFreq += sampleValue.getFrequency();
            if (countFreq > dice) {
                break;
            }
            lastValue = sampleValue.getValue();
        }
        return lastValue;
    }

    public Set<String> getRandomSampleValues(int numberOfValues) {
        if (numberOfValues < 0) throw new IndexOutOfBoundsException();
        if (numberOfValues >= this.sampleValues.size()) return this.sampleValues.keySet();
        
        Set<String> tempSet = new HashSet<String>();
        int num = numberOfValues < this.sampleValues.size()/2 ? numberOfValues : this.sampleValues.size() - numberOfValues;

        boolean done;
        for (int i = 0; i < num; i++) {
            done = false;
            while (!done) {
                done = tempSet.add(this.getRandomSampleValue());
            }
        }
        if (num == numberOfValues) return tempSet;
        else {
            Set<String> returnResult = new HashSet<String>();
            for (String value : this.sampleValues.keySet()) {
                if (!tempSet.contains(value)) {
                    returnResult.add(value);
                }
            }
            return returnResult;
        }
    }
    // </editor-fold>

    public Attribute(IPath path, IEntity entity) {
        this.path = path;
        this.entity = entity;
    }
}

class AttributeFrequencyComparator implements Comparator<Attribute> {

        @Override
        public int compare(Attribute o1, Attribute o2) {
            return o2.getFrequency() - o1.getFrequency();
        }

    }
